home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / misc / unix / unix_boot.lha / src / rel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-09  |  14.1 KB  |  435 lines

  1. /*
  2.  *    Copyright (C) 1991, Commodore Business Machines, Inc.
  3.  *
  4.  *    Given a pointer to an ELF file that has been loaded into
  5.  *    memory, and a pointer to a structure which contains, among
  6.  *    other things, the virtual address to which the start of text
  7.  *    is to be bound, performs relocation for the text and data
  8.  *    segments, and fills in other fields in the passed ELF file
  9.  *    info structure.
  10.  *
  11.  *    The text segment is bound to the specified starting virtual
  12.  *    address, followed immediately by initialized data, and then
  13.  *    uninitialized data.  Certain assumptions are made about the
  14.  *    existance and ordering of the text, data, and bss sections.
  15.  *    There are other limitations, such as only handling the
  16.  *    minimal number of relocation types necessary.
  17.  *
  18.  */
  19.  
  20. #if (DBUG || TEST)
  21. #  include <stdio.h>
  22. #endif
  23.  
  24. #if DBUG
  25. #  include <local/dbug.h>
  26. #else
  27. #  define DBUG_ENTER(a1)
  28. #  define DBUG_RETURN(a1) return(a1)
  29. #  define DBUG_VOID_RETURN return
  30. #  define DBUG_EXECUTE(keyword,a1)
  31. #  define DBUG_PRINT(keyword,arglist)
  32. #  define DBUG_PUSH(a1)
  33. #  define DBUG_POP()
  34. #  define DBUG_PROCESS(a1)
  35. #  define DBUG_FILE (stderr)
  36. #  define DBUG_SETJMP setjmp
  37. #  define DBUG_LONGJMP longjmp
  38. #endif
  39.  
  40. #include <elf.h>
  41. #include <sys/elf_68K.h>
  42.  
  43. #include <exec/types.h>
  44. #include <inline/exec.h>
  45.  
  46. #include "bootdata.h"
  47.  
  48. #if TEST
  49. #  define COMPLAIN(fmt,arg)    fprintf(stderr,fmt,arg)
  50. #  define RELOC(string)        string
  51. #else
  52. #  include <exec/alerts.h>
  53. #  define COMPLAIN(fmt,arg)    Alert(0x52454C41|AT_DeadEnd,0x4)
  54. #  define RELOC(string)        reloc(string)
  55. #endif
  56.  
  57. #if !TEST
  58. #define reloc(adr) (adr)
  59. #endif
  60.  
  61. extern int streq (char *s1, char *s2);
  62. extern int streqn (char *s1, char *s2, int nbytes);
  63.  
  64. struct globals {
  65.     char *elfdata;        /* Pointer to in memory file copy */
  66.     Elf32_Ehdr *Ehdr;        /* Pointer to ELF file header */
  67.     Elf32_Shdr *Shdrs;        /* Pointer to ELF section header table */
  68.     Elf32_Phdr *Phdrs;        /* Pointer to ELF program header table */
  69.     Elf32_Shdr *thdr;        /* Pointer to text section header */
  70.     Elf32_Shdr *dhdr;        /* Pointer to data section header */
  71.     Elf32_Shdr *bhdr;        /* Pointer to bss section header */
  72.     Elf32_Shdr *symhdr;        /* Pointer to symbol table section header */
  73.     Elf32_Addr end;        /* Current end of text+data+bss */
  74. };
  75.  
  76. struct nrel {
  77.     unsigned long nr_offset;
  78.     unsigned long nr_value;
  79. };
  80.  
  81. static Elf32_Addr symvaddr (struct globals *gbls, Elf32_Sym *sym,
  82.                 unsigned int symidx)
  83. {
  84.     Elf32_Shdr *rshdr;
  85.     Elf32_Addr vaddr = 0;
  86.  
  87.     DBUG_ENTER ("symvaddr");
  88.     if (sym -> st_shndx > 0 && sym -> st_shndx < gbls -> Ehdr -> e_shnum) {
  89.     DBUG_PRINT ("symdef", ("defined in section %d", sym -> st_shndx));
  90.     rshdr = gbls -> Shdrs + sym -> st_shndx;
  91.     if (rshdr -> sh_addr == 0) {
  92.         COMPLAIN ("symbol[%d] is", symidx);
  93.         COMPLAIN (" in unbound section %d\n", sym -> st_shndx);
  94.     } else {
  95.         vaddr = rshdr -> sh_addr + sym -> st_value;
  96.     }
  97.     } else if (sym -> st_shndx == SHN_ABS) {
  98.     DBUG_PRINT ("abssym", ("is an absolute symbol"));
  99.     vaddr = sym -> st_value;
  100.     } else {
  101.     COMPLAIN ("symbol[%d]", symidx);
  102.     COMPLAIN (" references section %d\n", sym -> st_shndx);
  103.     }
  104.     DBUG_PRINT ("symval", ("symbol[%d] value is %#lx", symidx, vaddr));
  105.     DBUG_RETURN (vaddr);
  106. }
  107.  
  108. static int relocsection (struct globals *gbls, Elf32_Shdr *shdr,
  109.              Elf32_Shdr *relsechdr, Elf32_Shdr *symtabhdr)
  110. {
  111.     char *secdata;
  112.     char *datap;
  113.     Elf32_Sym *syms;
  114.     Elf32_Sym *sym;
  115.     Elf32_Rela *relp;
  116.     Elf32_Addr vaddr;
  117.     unsigned int nrel;
  118.     int reltype;
  119.     unsigned int symidx;
  120.  
  121.     
  122.     DBUG_ENTER ("relocsection");
  123.     secdata = (char *) (gbls -> elfdata + relsechdr -> sh_offset);
  124.     syms = (Elf32_Sym *) (gbls -> elfdata + symtabhdr -> sh_offset);
  125.     relp = (Elf32_Rela *) (gbls -> elfdata + shdr -> sh_offset);
  126.     nrel = shdr -> sh_size / shdr -> sh_entsize;
  127.     DBUG_PRINT ("nrel", ("section has %u relocation records", nrel));    
  128.     while (nrel-- > 0) {
  129.     reltype = ELF32_R_TYPE (relp -> r_info);
  130.     symidx = ELF32_R_SYM (relp -> r_info);
  131.     sym = syms + symidx;
  132.     datap = secdata + relp -> r_offset;
  133.     vaddr = symvaddr (gbls, sym, symidx);
  134.     switch (reltype) {
  135.         case R_68K_32:
  136.         *(long *)datap = vaddr + relp -> r_addend;
  137.         DBUG_PRINT ("reloc", ("reloc to %#lx", *(long *)datap));
  138.         break;
  139.         default:
  140.         COMPLAIN ("unknown relocation type %d\n", reltype);
  141.         break;
  142.     }
  143.     relp++;
  144.     }
  145.     DBUG_RETURN (0);
  146. }
  147.  
  148. static int allocbss (struct globals *gbls)
  149. {
  150.     Elf32_Sym *syms;
  151.     Elf32_Sym *sym;
  152.     Elf32_Addr vaddr;
  153.     unsigned int nsyms;
  154.     unsigned int symidx;
  155.  
  156.     DBUG_ENTER ("allocbss");
  157.     nsyms = gbls -> symhdr -> sh_size / gbls -> symhdr -> sh_entsize;
  158.     DBUG_PRINT ("nsyms", ("found %#x symbols", nsyms));
  159.     syms = (Elf32_Sym *) (gbls -> elfdata + gbls -> symhdr -> sh_offset);
  160.     for (symidx = 0; symidx < nsyms; symidx++) {
  161.     sym = syms + symidx;
  162.     if (sym -> st_shndx == SHN_COMMON) {
  163.         if (gbls -> bhdr == NULL) {
  164.         COMPLAIN ("symbol[%d] in missing bss section\n", symidx);
  165.         break;
  166.         } else {
  167.         sym -> st_shndx = gbls -> bhdr - gbls -> Shdrs;
  168.         vaddr = gbls -> bhdr -> sh_addr + gbls -> bhdr -> sh_size;
  169.         vaddr += (sym -> st_value - 1);
  170.         vaddr &= ~(sym -> st_value - 1);
  171.         DBUG_PRINT ("bss", ("alloc sym[%d] at bss vaddr %#lx",
  172.                     symidx, vaddr));
  173.         sym -> st_value = vaddr - gbls -> bhdr -> sh_addr;
  174.         gbls -> end = vaddr + sym -> st_size;
  175.         DBUG_PRINT ("end", ("end moved to %#lx", gbls -> end));
  176.         gbls -> bhdr -> sh_size = gbls -> end - gbls -> bhdr -> sh_addr;
  177.         }
  178.     }
  179.     }
  180.     DBUG_RETURN (0);
  181. }
  182.  
  183. static int specialsyms (struct globals *gbls)
  184. {
  185.     Elf32_Sym *syms;
  186.     Elf32_Sym *sym;
  187.     Elf32_Addr vaddr;
  188.     unsigned int nsyms;
  189.     unsigned int symidx;
  190.     Elf32_Shdr *strtabhdr;
  191.     char *strtab;
  192.     char *symname;
  193.  
  194.     DBUG_ENTER ("specialsyms");
  195.     nsyms = gbls -> symhdr -> sh_size / gbls -> symhdr -> sh_entsize;
  196.     DBUG_PRINT ("nsyms", ("found %#x symbols", nsyms));
  197.     syms = (Elf32_Sym *) (gbls -> elfdata + gbls -> symhdr -> sh_offset);
  198.     strtabhdr = gbls -> Shdrs + gbls -> symhdr -> sh_link;
  199.     strtab = gbls -> elfdata + strtabhdr -> sh_offset;
  200.     for (symidx = 0; symidx < nsyms; symidx++) {
  201.     sym = syms + symidx;
  202.     if (sym -> st_name) {
  203.         symname = strtab + sym -> st_name;
  204.         DBUG_PRINT ("sym", ("symbol[%d] = '%s'", symidx, symname));
  205.         if (streq (symname, RELOC ("etext"))) {
  206. #if 0
  207.         sym -> st_value = gbls -> thdr -> sh_addr + gbls -> thdr -> sh_size;
  208. #endif
  209.         sym -> st_shndx = SHN_ABS;
  210.         } else if (streq (symname, RELOC ("edata"))) {
  211.         sym -> st_value = gbls -> dhdr -> sh_addr + gbls -> dhdr -> sh_size;
  212.         sym -> st_shndx = SHN_ABS;
  213.         } else if (streq (symname, RELOC ("end"))) {
  214.         sym -> st_value = gbls -> end;
  215.         sym -> st_shndx = SHN_ABS;
  216.         }
  217.     }
  218.     }
  219.     DBUG_RETURN (0);
  220. }
  221.  
  222. static int findsections (struct BootData *bip, struct globals *gbls)
  223. {
  224.     unsigned int sectnum;
  225.     Elf32_Shdr *shdr;
  226.     Elf32_Shdr *strtabhdr;
  227.     char *strtab;
  228.     char *sectname;
  229.     
  230.     DBUG_ENTER ("findsections");
  231.     DBUG_PRINT ("sects", ("look at %d sections", gbls -> Ehdr -> e_shnum));
  232.     strtabhdr = gbls -> Shdrs + gbls -> Ehdr -> e_shstrndx;
  233.     strtab = gbls -> elfdata + strtabhdr -> sh_offset;
  234.     for (sectnum = 0; sectnum < gbls -> Ehdr -> e_shnum; sectnum++) {
  235.     shdr = gbls -> Shdrs + sectnum;
  236.     sectname = strtab + shdr -> sh_name;
  237.     DBUG_PRINT ("sect", ("section[%d] '%s'", sectnum, sectname));
  238.     if (shdr -> sh_type == SHT_PROGBITS) {
  239.         if (shdr -> sh_flags & SHF_EXECINSTR) {
  240.         if (shdr -> sh_size > 0) {
  241.             gbls -> thdr = shdr;
  242.         }
  243.         } else if (shdr -> sh_flags & SHF_WRITE) {
  244.         if (shdr -> sh_size > 0) {
  245.             gbls -> dhdr = shdr;
  246.         }
  247.         }
  248.     } else if (shdr -> sh_type == SHT_NOBITS) {
  249.         if (shdr -> sh_flags & SHF_WRITE) {
  250.         if (shdr -> sh_size > 0) {
  251.             gbls -> bhdr = shdr;
  252.         }
  253.         }
  254.     } else if (shdr -> sh_type == SHT_SYMTAB) {
  255.         gbls -> symhdr = shdr;
  256.     }
  257.     }
  258.     DBUG_RETURN (0);
  259. }
  260.  
  261. static int bindsections (struct BootData *bip, struct globals *gbls)
  262. {
  263.     unsigned int sectnum;
  264.     Elf32_Shdr *shdr;
  265.     Elf32_Shdr *strtabhdr;
  266.     char *strtab;
  267.     char *sectname;
  268.     
  269.     DBUG_ENTER ("bindsections");
  270.     if (gbls -> thdr != NULL) {
  271.     gbls -> thdr -> sh_addr = bip -> bd_entry;
  272.     DBUG_PRINT ("text", ("text @ %#lx", gbls -> thdr -> sh_addr));
  273.     DBUG_PRINT ("text", ("text size %#lx", gbls -> thdr -> sh_size));
  274.     bip -> bd_tvaddr = gbls -> thdr -> sh_addr;
  275.     bip -> bd_toffset = gbls -> thdr -> sh_offset;
  276.     bip -> bd_tsize = gbls -> thdr -> sh_size;
  277.     gbls -> end = gbls -> thdr -> sh_addr + gbls -> thdr -> sh_size;
  278.     DBUG_PRINT ("end", ("end = %#lx", gbls -> end));
  279.     if (gbls -> dhdr != NULL) {
  280.         gbls -> dhdr -> sh_addr = gbls -> thdr -> sh_addr + gbls -> thdr -> sh_size;
  281.         DBUG_PRINT ("data", ("data @ %#lx", gbls -> dhdr -> sh_addr));
  282.         DBUG_PRINT ("data", ("data size %#lx", gbls -> dhdr -> sh_size));
  283.         bip -> bd_dvaddr = gbls -> dhdr -> sh_addr;
  284.         bip -> bd_doffset = gbls -> dhdr -> sh_offset;
  285.         bip -> bd_dsize = gbls -> dhdr -> sh_size;
  286.         gbls -> end = gbls -> dhdr -> sh_addr + gbls -> dhdr -> sh_size;
  287.         DBUG_PRINT ("end", ("end = %#lx", gbls -> end));
  288.         if (gbls -> bhdr != NULL) {
  289.         gbls -> bhdr -> sh_addr = gbls -> dhdr -> sh_addr + gbls -> dhdr -> sh_size;
  290.         gbls -> end = gbls -> bhdr -> sh_addr + gbls -> bhdr -> sh_size;
  291.         DBUG_PRINT ("bss", ("bss @ %#lx", gbls -> bhdr -> sh_addr));
  292.         DBUG_PRINT ("bss", ("bss size %#lx", gbls -> bhdr -> sh_size));
  293.         DBUG_PRINT ("end", ("end = %#lx", gbls -> end));
  294.         }
  295.     }
  296.     }
  297.     strtabhdr = gbls -> Shdrs + gbls -> Ehdr -> e_shstrndx;
  298.     strtab = gbls -> elfdata + strtabhdr -> sh_offset;
  299.     for (sectnum = 0; sectnum < gbls -> Ehdr -> e_shnum; sectnum++) {
  300.     shdr = gbls -> Shdrs + sectnum;
  301.     sectname = strtab + shdr -> sh_name;
  302.     DBUG_PRINT ("sect", ("section[%d] '%s'", sectnum, sectname));
  303.     if (streq (sectname, RELOC (".uvblock"))) {
  304.         shdr -> sh_addr = 0x40000000;
  305.         DBUG_PRINT ("sect", (".uvblock bound to %#lx", shdr -> sh_addr));
  306.     } else if (streq (sectname, RELOC (".kvsysseg"))) {
  307.         shdr -> sh_addr = 0x40040000;
  308.         DBUG_PRINT ("sect", (".kvsysseg bound to %#lx", shdr -> sh_addr));
  309.     } else if (streq (sectname, RELOC (".kvsegmap"))) {
  310.         shdr -> sh_addr = 0x40440000;
  311.         DBUG_PRINT ("sect", (".kvsegmap bound to %#lx", shdr -> sh_addr));
  312.     } else if (streq (sectname, RELOC (".kvsegu"))) {
  313.         shdr -> sh_addr = 0x48440000;
  314.         DBUG_PRINT ("sect", (".kvsegu bound to %#lx", shdr -> sh_addr));
  315.     }
  316.     }
  317.     DBUG_RETURN (0);
  318. }
  319.  
  320. static int relocsections (struct BootData *bip, struct globals *gbls)
  321. {
  322.     unsigned int sectnum;
  323.     Elf32_Shdr *shdr;
  324.     Elf32_Shdr *symtabhdr;
  325.     Elf32_Shdr *relsechdr;
  326.  
  327.     DBUG_ENTER ("relocsections");
  328.     for (sectnum = 0; sectnum < gbls -> Ehdr -> e_shnum; sectnum++) {
  329.     shdr = gbls -> Shdrs + sectnum;
  330.     DBUG_PRINT ("sectoff", ("sect @ offset %#lx", shdr -> sh_offset));
  331.     if (shdr -> sh_type == SHT_RELA) {
  332.         DBUG_PRINT ("rela", ("found relocation section"));
  333.         symtabhdr = gbls -> Shdrs + shdr -> sh_link;
  334.         relsechdr = gbls -> Shdrs + shdr -> sh_info;
  335.         relocsection (gbls, shdr, relsechdr, symtabhdr);
  336.     }    
  337.     }
  338.     DBUG_RETURN (0);
  339. }
  340.  
  341. static void compactreloc (struct globals *gbls)
  342. {
  343.     Elf32_Shdr *relshdr;
  344.     struct nrel *nrelp;
  345.     unsigned int nrelcount;
  346.     char *textbase;
  347.     unsigned long relvalue;
  348.     unsigned long offset;
  349.  
  350.     DBUG_ENTER ("compactreloc");
  351.     relshdr = gbls -> Shdrs + 3;
  352.     nrelcount = relshdr -> sh_size / relshdr -> sh_entsize;
  353.     DBUG_PRINT ("nrelcount", ("found %d reloc entries", nrelcount));
  354.     nrelp = (struct nrel *) (gbls -> elfdata + relshdr -> sh_offset);
  355.     textbase = gbls -> elfdata + gbls -> thdr -> sh_offset;
  356.     while (nrelcount-- != 0) {
  357.     relvalue = nrelp -> nr_value;
  358.     offset = nrelp -> nr_offset;
  359.     if (!(offset & 0x80000000)) {
  360.         relvalue += gbls -> thdr -> sh_addr;
  361.     }
  362.     DBUG_PRINT ("rel", ("text[%x] = %x", offset & 0x7FFFFFFF, relvalue));
  363.     *(long *)(textbase + (offset & 0x7FFFFFFF)) = relvalue;
  364.     nrelp++;
  365.     }
  366.     DBUG_VOID_RETURN;
  367. }
  368.  
  369. /*
  370.  *    Note that if the ELF file is fully executable (all relocation
  371.  *    already done, the first entry in the program header table is
  372.  *    presumed to be the entry for the combined text and data segment.
  373.  *    This is true with the current development tools and procedures,
  374.  *    but is not required by the ELF format.  Should be fixed.
  375.  */
  376.  
  377. int rel (char *elfdata, Elf32_Addr vaddr, struct BootData *bip)
  378. {
  379.     struct globals gblvars;
  380.     Elf32_Shdr *shdr;
  381.     int rtnval = 1;
  382.  
  383.     DBUG_ENTER ("rel");
  384.     DBUG_PRINT ("vaddr", ("text starts at %#lx", vaddr));
  385.     gblvars.Ehdr = (Elf32_Ehdr *) elfdata;
  386.     if (!streqn ((char *) (gblvars.Ehdr -> e_ident), RELOC (ELFMAG), SELFMAG)) {
  387.     DBUG_PRINT ("elf", ("found a non-ELF format file"));
  388.     COMPLAIN ("found a non-ELF format file\n", 0);
  389.     rtnval = 0;    
  390.     } else if (gblvars.Ehdr -> e_type == ET_EXEC) {
  391.     DBUG_PRINT ("elf", ("found an executable, fully linked file"));
  392.     gblvars.Phdrs = (Elf32_Phdr *) (elfdata + gblvars.Ehdr -> e_phoff);
  393.     bip -> bd_entry = gblvars.Ehdr -> e_entry;
  394.     bip -> bd_tvaddr = gblvars.Phdrs -> p_vaddr;
  395.     bip -> bd_toffset = gblvars.Phdrs -> p_offset;
  396.     bip -> bd_tsize = gblvars.Phdrs -> p_filesz;
  397.     bip -> bd_dvaddr = bip -> bd_tvaddr + bip -> bd_tsize;;
  398.     bip -> bd_doffset = bip -> bd_toffset + bip -> bd_tsize;
  399.     bip -> bd_dsize = 0;
  400.     } else if (gblvars.Ehdr -> e_type == ET_LOPROC) {
  401.     DBUG_PRINT ("elf", ("found an compact relocatable ELF file"));
  402.     gblvars.elfdata = elfdata;
  403.     gblvars.Shdrs = (Elf32_Shdr *) (gblvars.elfdata + gblvars.Ehdr -> e_shoff);
  404.     gblvars.thdr = gblvars.Shdrs + 1;
  405.     gblvars.thdr -> sh_addr = vaddr;
  406.     bip -> bd_entry = vaddr;
  407.     bip -> bd_tvaddr = vaddr;
  408.     bip -> bd_toffset = gblvars.thdr -> sh_offset;
  409.     bip -> bd_tsize = gblvars.thdr -> sh_size;
  410.     bip -> bd_dvaddr = bip -> bd_tvaddr + bip -> bd_tsize;
  411.     bip -> bd_doffset = bip -> bd_toffset + bip -> bd_tsize;
  412.     bip -> bd_dsize = 0;
  413.     compactreloc (&gblvars);
  414.     } else if (gblvars.Ehdr -> e_type == ET_REL) {
  415.     DBUG_PRINT ("elf", ("found a relocatable ELF file"));
  416.     bip -> bd_entry = vaddr;
  417.     gblvars.elfdata = elfdata;
  418.     gblvars.Shdrs = (Elf32_Shdr *) (gblvars.elfdata + gblvars.Ehdr -> e_shoff);
  419.     gblvars.thdr = NULL;
  420.     gblvars.dhdr = NULL;
  421.     gblvars.bhdr = NULL;
  422.     gblvars.end = 0;
  423.     findsections (bip, &gblvars);
  424.     bindsections (bip, &gblvars);
  425.     allocbss (&gblvars);
  426.     specialsyms (&gblvars);
  427.     relocsections (bip, &gblvars);
  428.     } else {
  429.     COMPLAIN ("ELF e_file type %d not handled\n", gblvars.Ehdr -> e_type);
  430.     rtnval = 0;
  431.     }
  432.     DBUG_RETURN (rtnval);
  433. }
  434.  
  435.